import pickle
from random import randrange
from numpy.core.shape_base import block
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from numpy import floor
from numpy import abs
from numpy import sin
from numpy import cos
from numpy import radians
import timew
from perlin_noise import PerlinNoise
from nMap import nMap
from cave_system import Caves
from tree_system import Trees
from mining_system import Mining_system

# from safe_combine import safe_combine

# 创建ursina窗口
app = Ursina()

# 关于第一人称操作设置
subject = FirstPersonController()
# 隐藏鼠标指针
subject.cursor.visible = False
# 重力，初始位置设置
subject.gravity = 0
# 下降速度重力加速度
grav_speed = 0
grav_acc = 0.1
subject.x = subject.z = 5
subject.y = 32
prevZ = subject.z
prevX = subject.x
origin = subject.position  # Vec3 object? .x .y .z

# 图片素材对象
grassStrokeTex = 'grass_14.png'
monoTex = 'stroke_mono.png'
stoneTex = 'grass_mono.png'

cubeTex = 'block_texture.png'
cubeModel = 'moonCube'

axoTex = 'axolotl.png'
axoModel = 'axolotl.obj'

axeModel = 'Diamond-Pickaxe'
axeTex = 'diamond_axe_tex'

noise = PerlinNoise(octaves=1, seed=int(randrange(99, 111)))
seedMouth = Text(text='<pink><bold>your seed today,sir,is ' +
                      str(noise.seed),background=True)
seedMouth.background.color=color.orange
seedMouth.scale*=1.4
seedMouth.x=-0.52
seedMouth.y=0.4
seedMouth.appear(speed=0.15)


#print('seed is ' + str(noise.seed))
megasets = []  # 创建一个大型集
subsets = []
subCubes = []
# New variables :)
generating = 1  # -1 if off.
canGenerate = 1  # -1 if off.
genSpeed = 0
perCycle = 64
currentCube = 0
currentSubset = 0
currentMegaset = 0
numSubCubes = 64
numSubsets = 10  # 多少组成一个巨型集
theta = 0
rad = 0
# 记录地形块是否存在的字典
# 在密钥中指定的位置。
subDic = {}

def createTerrainEntities():

    # Instantiate our 'ghost' subset cubes.
    # 实例化我们的“幽灵”子集立方体。
    for i in range(numSubCubes):
        bud = Entity(model=cubeModel, texture=cubeTex)
        bud.scale *= 0.99999
        bud.rotation_y = random.randint(1, 4) * 90
        bud.disable()
        subCubes.append(bud)

    # 实例化我们的空子集。
    for i in range(numSubsets):
        bud = Entity(model=cubeModel)
        bud.texture = cubeTex
        bud.disable()
        subsets.append(bud)

    # 实例化我们的巨型集。
    for i in range(99):
        bud = Entity(model=cubeModel)
        bud.texture = cubeTex
        bud.scale *= 0
        bud.disable()
        megasets.append(bud)

createTerrainEntities()

#保存文件功能
def save():
    global subDic,megasets,subsets,subCubes,noise
    import pickle,os,sys
    #创建一个新的实体保存
    #首先，打开/创建一个文件
    path =os.path.dirname(os.path.abspath(sys.argv[0]))
    os.chdir(path)
    with open('pickling.txt','wb') as f:
        e = Entity()
        for s in subsets:
            if s.enabled == True:
                s.parent = e
        for m in megasets:
            if m.enabled == True:
                m.parent = e

        e.combine(auto_destroy=False)

        terrainModel = [e.model.vertices,
                        e.model.triangles,
                        e.model.colors,
                        e.model.uvs]

        bulidsModel=[varch.builds.model.vertices,
                        varch.builds.model.triangles,
                        varch.builds.model.colors,
                        varch.builds.model.uvs]

        for s in subsets:
            s.parent = scene
        for m in megasets:
            m.parent = scene
        destroy(e)

        newlist = [subject.position,
                   varch.tDic,
                   subDic,
                   terrainModel,
                   noise,
                   bulidsModel
                   ]

        pickle.dump(newlist,f)
        #清除临时列表
        newlist.clear()
        terrainModel.clear()

def load():
    import pickle,sys,os
    global subDic,rad,theta,currentSubset
    global currentCube,currentMegaset,noise
    global generating,canGenerate
    path=os.path.dirname(os.path.abspath(sys.argv[0]))
    os.chdir(path)

    with open('pickling.txt','rb') as f:
        nd=pickle.load(f)

        subject.position=copy(nd[0])
        varch.tDic=copy(nd[1])
        subDic=copy(nd[2])
        tm=copy(nd[3])
        noise=copy(nd[4])
        bm=copy(nd[5])

        #删除所有的当前地形
        for s in subCubes:
            destroy(s)
        for s in subsets:
            destroy(s)
        for m in megasets:
            destroy(m)
        destroy(varch.builds)
        subCubes.clear()
        subsets.clear()
        megasets.clear()

        createTerrainEntities()
        megasets[0]=Entity(model=Mesh(
                            vertices=tm[0],
                            triangles=tm[1],
                            colors=tm[2],
                            uvs=tm[3]),
                            texture=cubeTex
                          )
        varch.builds=Entity(model=Mesh(
                            vertices=bm[0],
                            triangles=bm[1],
                            colors=bm[2],
                            uvs=bm[3]),
                            texture=cubeTex
                            )
        currentCube=0
        currentMegaset=1
        currentSubset=0
        currentSubset=0
        rad=0
        theta=0
        generating=-1
        canGenerate=-1
        subject.rotation_x=0.0


# 将石搞放到玩家面前的正确位置
axe = Entity(model=axeModel,
             texture=axeTex,
             scale=0.07,
             position=subject.position,
             always_on_top=True)

sol4r = Trees()
# 创建叫anush的洞穴对象
anush = Caves()
# mining system
varch = Mining_system(subject, axe ,camera, subsets,megasets)


# 场景天空颜色
window.color = color.rgb(0, 200, 211)
#window.color = color.rgb(0, 0, 0)
# 界面关闭按钮取消
window.exit_button.visible = False

prevTime = time.time()
# 场景方块颜色
scene.fog_color = color.rgb(0, 222, 0)
# 场景方块大小
scene.fog_density = 0.02

#load()

# 捕捉键盘输入操作
def input(key):
    global generating, canGenerate
    # 获取全局变量的建造距离

    # 处理mining system的key inputs
    varch.input(key)

    # 在构建模式下暂停自动生成地形。
    # 退出构建模式，会继续生成地图
    if varch.buildMode == 1:
        generating = -1
        canGenerate = -1

    if key == 'q' or key == 'escape':
        quit()
    if key == 'g':
        generating *= -1
        canGenerate *= -1

    if key == 'b':
        save()

    if key=='n':
        load()



def update():
    global prevZ, prevX, prevTime, genSpeed, perCycle
    global rad, origin, generating, canGenerate,theta
    global canGenerate,generating
    if abs(subject.z - prevZ) > 1 or \
            abs(subject.x - prevX) > 1:
        origin = subject.position
        rad = 0
        theta = 0  # 重置theta极坐标
        generating = 1 * canGenerate
        prevZ = subject.z
        prevX = subject.x

    generateShell()

    if time.time() - prevTime > genSpeed:
        for i in range(perCycle):
            genTerrain()
        prevTime = time.time()

    vincent.look_at(subject, 'forward')  # 使vincent（巨型鸡）转向主体
    vincent.rotation_z = 0;
    # vincent.rotation_x = 0

    # 控制挖掘和构建功能
    varch.buildTool()





# 新的起伏逻辑
def genPerlin(_x, _z, plantTree=False):
    y = 0
    freq = 64
    amp = 42
    y += ((noise([_x / freq, _z / freq])) * amp)
    freq = 32
    amp = 21
    y += ((noise([_x / freq, _z / freq])) * amp)

    # 这里是否有一个洞穴
    # 有的话降低32或者其他高度
    # git测试
    whatCaveHeight = anush.checkCave(_x, _z)
    if whatCaveHeight != None:
        y = whatCaveHeight
    elif plantTree == True:
        sol4r.checkTree(_x, y, _z)

    return floor(y)


# 新的地形函数
def genTerrain():
    global currentCube, theta, rad, currentSubset
    global generating,currentMegaset

    if generating == -1: return

    # Decide where to place new terrain cube!
    x = floor(origin.x + sin(radians(theta)) * rad)
    z = floor(origin.z + cos(radians(theta)) * rad)
    # Check whether there is terrain here already...
    if subDic.get('x' + str(x) + 'z' + str(z)) != 'i':
        subCubes[currentCube].enable()
        subCubes[currentCube].x = x
        subCubes[currentCube].z = z

        subCubes[currentCube].parent = subsets[currentSubset]
        y = subCubes[currentCube].y = genPerlin(x, z, True)
        # 记录位置在字字典，和挖掘系统的字典
        subDic['x' + str(x) + 'z' + str(z)] = 'i'
        varch.tDic['x' + str(x) + 'y' + str(y) + 'z' + str(z)] = y
        # 选择颜色
        c = nMap(y, -8, 21, 132, 212)  # 改变地形颜色
        c += random.randint(-32, 32)  # 随机获得一个整数
        subCubes[currentCube].color = color.rgb(c, c, c)
        subCubes[currentCube].disable()
        currentCube += 1

        # 准备好构建一个子集吗？
        if currentCube == numSubCubes:

            subsets[currentSubset].combine(auto_destroy=False)
            subsets[currentSubset].enable()
            currentSubset += 1
            currentCube = 0

            # 准备好建一个巨型集了吗
            if currentSubset == numSubsets:


                #megasets.append(Entity(model=cubeModel, texture=cubeTex))


                # 所有子集都是新巨型集的父集
                for s in subsets:
                    s.parent = megasets[currentMegaset]
                megasets[currentMegaset].combine(auto_destroy=False)
                for s in subsets:
                    s.parent = scene
                    #s.disable()
                currentSubset = 0
                currentMegaset+=1
                print('Megasets #' + str(len(megasets)) + '!')

    else:
        pass
        # There was terrain already there, so
        # continue rotation to find new terrain spot.

    if rad > 0:
        theta += 45 / rad
    else:
        rad += 0.5

    if theta >= 360:
        theta = 0
        rad += 0.5


# 新的重力系统来移动
def generateShell():
    # 这个位置的地形是什么Y？
    global subject, grav_speed, grav_acc

    #’新‘的新系统
    # 我们可以下架多高/多低
    step_height = 5
    subjectHeight = 2
    gravityON = True

    target_y = subject.y

    for i in range(step_height, -step_height, -1):
        # 这个位置的地形是多少？
        # terra = genPerlin(subject.x,subject.z)
        terra = varch.tDic.get('x' + str((floor(subject.x+0.5))) +
                               'y' + str((floor(subject.y + i))) +
                               'z' + str((floor(subject.z+0.5))))

        #超越台阶高度---可能迫使我们
        # 穿过地形底部
        terraTop = varch.tDic.get('x' + str((floor(subject.x + 0.5))) +
                               'y' + str((floor(subject.y + i+1))) +
                               'z' + str((floor(subject.z + 0.5))))
        if terra != None and terra != 'gap':
            gravityON = False
            if terraTop == None or terraTop == 'rap':
                # print('TERRAIN FOUND! ' + str(terra + 2))
                target_y = floor(subject.y + i) + subjectHeight
                break

            #搭建了一个很高的塔，就让人爬不上去，调整玩家位置
            subject.x -= 0.6
            subject.z -= 0.6

    if gravityON == True:
        # This means we're falling!
        grav_speed += (grav_acc * time.dt)
        subject.y -= grav_speed
    else:
        subject.y = lerp(subject.y, target_y, 9.807 * time.dt)
        grav_speed = 0  # 重置重力速度：gfloored.

    #'新‘的旧系统
    '''
    # 我们可以下架多高/多低
    step_height = 5

    target_y = genPerlin(subject.x, subject.z) + 2
    # 我们离目标有多远
    target_dist = target_y - subject.y
    # 我们能加强吗？
    if target_dist < step_height and target_dist > -step_height:
        subject.y = lerp(subject.y, target_y, 9.807 * time.dt)
    elif target_dist < - step_height:
        # 此时我们在坠落
        grav_speed += (grav_acc * time.dt)
        subject.y -= grav_speed
    '''
    # global shellWidth
    # for i in range(len(shellies)):
    #     x = shellies[i].x = floor((i / shellWidth) +
    #                               subject.x - 0.5 * shellWidth)
    #     z = shellies[i].z = floor((i % shellWidth) +
    #                               subject.z - 0.5 * shellWidth)
    #     shellies[i].y = genPerlin(x, z)



# 调整镐的位置看起来像自己手持
axe.x -= 3
axe.z -= 2
axe.y -= subject.y
axe.rotation_z = 90
axe.rotation_y = 180
axe.parent = camera
# 加载大公鸡模型，贴图模型都在asset中engine会自动寻找，直接写代码即可
chickenModel = load_model('chicken.obj')
vincent = Entity(model=chickenModel, scale=1,
                 x=22, z=16, y=4,
                 texture='chicken.png',
                 double_sided=True)
# 加载巨型蝾螈
baby = Entity(model=axoModel, scale=10,
              x=-22, z=16, y=4,
              texture=axoTex,
              double_sided=True)

generateShell()

app.run()
